package com.smtx.utils.iterator;

import java.util.*;

/**
 * Created by IntelliJ IDEA.
 * User: repnikov
 * Date: 08.04.11
 * Time: 0:40
 * To change this template use File | Settings | File Templates.
 */
public class ExtIterator<X> implements Iterator<X> {
    protected Iterator<X> iterator;
    protected List<Iterator<X>> iterators;
    protected Set<Filter> filters = new HashSet<Filter>();
    protected X current;
    protected boolean isSetCurrent = false;

    private ExtIterator() {}

    public static <T> ExtIterator<T> create(Iterator<T> iterator) {
        ExtIterator<T> it = new ExtIterator<T>();
        it.iterators = new ArrayList<Iterator<T>>();
        it.iterators.add(iterator);
        return it;
    }

    /*@SuppressWarnings("unchecked")
    public static ExtIterator create(Iterator iterator) {
        return create(iterator, Object.class);
    }*/

    public boolean hasNext() {
        if (getIterator() == null) return false;
        if (isSetCurrent) return true;
        if (getIterator().hasNext()) {
            boolean found = true;
            while (getIterator().hasNext()) {
                setCurrent( getIterator().next() );
                if (!filter(current)) break;
                if (!getIterator().hasNext()) {
                    found = false;
                    getCurrent();
                }
            }
            return found;
        } else
            return false;
    }

    public X next() {
        return hasNext() ? getCurrent() : null;
    }

    public void remove() {
        if (iterator != null)
            iterator.remove();
    }

    public void addKeepFilter(Filter filter) {
        filter.setType(Filter.FilterType.KEEP);
        filters.add(filter);
    }
    public void addDropFilter(Filter filter) {
        filter.setType(Filter.FilterType.REMOVE);
        filters.add(filter);
    }

    public ExtIterator<X> keepFilter(Filter filter) {
        ExtIterator<X> it = ExtIterator.<X>create( this );
        it.addKeepFilter(filter);
        return it;
    }
    public ExtIterator<X> dropFilter(Filter filter) {
        ExtIterator<X> it = ExtIterator.<X>create( this );
        it.addDropFilter(filter);
        return it;
    }

    protected boolean filter(Object o) {
        boolean res = true;
        for (Filter f : filters) {
            res = f.getType().equals(Filter.FilterType.KEEP) ? f.filter(o) :
                !f.filter(o);
            if (!res) break;
        }
        return res;
    }

    protected X getCurrent() {
        isSetCurrent = false;
        X item = current;
        current = null;
        return item;
    }

    protected void setCurrent(X current) {
        this.current = current;
        isSetCurrent = true;
    }

    private Iterator<X> getIterator() {
        while ((iterator == null || !iterator.hasNext()) && iterators.size() > 0) {
            iterator = iterators.remove(0);
        }
        return iterator;
    }

    public Collection<X> getAll() {
        List<X> res = new ArrayList<X>();
        while (hasNext()) {
            res.add( next() );
        }
        return res;
    }

    public List<X> toList() {
        return new ArrayList<X>( getAll() );
    }
    public Set<X> toSet() {
        return new HashSet<X>( getAll() );
    }
}
